/** @brief CWELD焊接单元
 * 
 * @version  0.1
 * @author   yangqiuyou
 * @date     2024.12.27
 *         _
 *     ___| |__   ___ _ __   __ _  ___  _ __   __ _
 *    / __| '_ \ / _ \ '_ \ / _` |/ _ \| '_ \ / _` |
 *    \__ \ | | |  __/ | | | (_| | (_) | | | | (_| |
 *    |___/_| |_|\___|_| |_|\__, |\___/|_| |_|\__, |
 *                          |___/             |___/
 * @copyright (c) 2025 by 神工仿真, All Rights Reserved.
 */
#pragma once

#include "Utility/Algebra/Point.h"
#include "DataStructure/Input/Element/CWELDData.h"

#include "DataStructure/Common/Id.h"
#include "../Common/ConnectElementExport.h"
#include "DataStructure/Input/Material/IsotropicMaterial.h"
#include "DataStructure/Input/Property/PBARData.h"
// #include "DataStructure/Input/Property/PBEAMData.h"
#include "SGFem/ElementCalculator/Interface/IElementCalculator.h"

SG_FEMSOLVER_ELEMENT_NAMESPACE_OPEN
class ConnectElement_DECLSPEC CweldCalculator : public SG::FEMSolver::Element::IElementCalculator
{
  public:
    CweldCalculator ();
    virtual ~CweldCalculator () = default;

    /** @brief 面的点集gSet求其法向量，内部会判断是3/4/6/8节点
     *
     * @param            gSet         面节点集，壳全局坐标
     * @param[out]       T            壳转换矩阵
     * @param[out]       origin       壳面中点与局部投影点的距离向量
     * @param[out]       localCoord   壳局部坐标
     * @author   yangqiuyou
     * @date     2025.05.15
     */
    static void ComputeSurfaceCoord (const SG::Algebra::PointArray& gSet,
                                    _OUT SG::Algebra::Matrix&       T, 
                                    _OUT SG::Algebra::Point&        origin,
                                    _OUT SG::Algebra::Matrix&       localCoord);

    /** @brief 寻找壳单元ID集ShIds中距离point点坐标最近的单元ShId(用于PARTPAT格式和CFAST单元中的PROP格式)
     *
     * @param       point      节点坐标
     * @param       ShIds      壳单元ID集
     * @param[out]  ShId       最近的壳单元Id
     * @author   zhangzhiyu
     * @date     2025.05.06
     */
    static void FindNearestElement (const SG::DBManager::DBServiceFactorySP dbServiceFactory,
                                    const SG::Algebra::Point& point,
                                    const SG::DataStructure::Common::IdArray& ShellGroup,
                                    _OUT  SG::DataStructure::Common::Id& TargetShellId);
  

    /** @brief 点GS到两个平面的投影点坐标GA, GB； 并且返回壳A的法线。（适用于ELEMID/GRIDID/ELPAT/PARTPAT）
     *
     * @param gS          投影辅助点GS点的坐标
     * @param gASet       壳节点Basic坐标
     * @param gBSet       壳节点Basic坐标
     * @param nA          壳单元A上的法向量
     * @param[out] GA     壳单元A上的投影点坐标GA
     * @param[out] GB     壳单元B上的投影点坐标GB
     * @author   zhangzhiyu
     * @date     2025.01.04
     */
    static void ComputeProjectionPoint2 (const SG::Algebra::Point       gS,
                                         const SG::Algebra::PointArray& gASet,
                                         const SG::Algebra::PointArray& gBSet,
                                         SG::Algebra::Point& _OUT       GA,
                                         SG::Algebra::Point& _OUT       GB,
                                         SG::Algebra::Vector3D&         nA);

    /// @brief 长度为零的CWELD梁刚度矩阵
    void ComputeStiffness0 (
        const SG::DataStructure::Common::Real&           L,
        const SG::DataStructure::FEM::IsotropicMaterial& material,
        const SG::DataStructure::FEM::PBARData&          property,
        _OUT SG::Algebra::Matrixd& kl);

    /// @brief  修正梁刚度矩阵
    /// @param L 
    /// @param material 
    /// @param property 
    /// @param kl 
    void ComputeStiffness1
        (
        const SG::DataStructure::Common::Real&           L,
        const SG::DataStructure::FEM::IsotropicMaterial& material,
        const SG::DataStructure::FEM::PBARData&         property,
        _OUT SG::Algebra::Matrixd&                       kl
        );

    /** @brief   建立参考面节点全局坐标系 和投影点basic坐标下位移约束方程
     *
     * @param         Gi                投影点全局坐标   
     * @param         projectdispCoodId 投影点位移输出坐标系ID
     * @param         plane             壳面节点全局坐标
     * @param         dispCoordset      平面连接节点的位移输出坐标系
     * @param[out]    R                 约束方程 s.t. uProj = R*u_Shell
     * @author   yangqiuyou
     * @date     2025.05.15
     */
    static void ComputeConstrantEquation (const SG::Algebra::Point&                 Gi,
                                          const SG::DataStructure::Common::Id&      projectdispCoodId,
                                          const SG::Algebra::PointArray&            plane,
                                          const SG::DataStructure::Common::IdArray& dispCoordset,
                                          SG::Algebra::Matrixd& _OUT                R);

    /** @brief        求解三角形约束方程
     *
     * @param         Gi            投影点全局坐标   
     * @param         planeGlobal   壳面节点全局坐标
     * @param[out]    T             壳面转换矩阵
     * @param[out]    R             R*[u_A; u_Shell_G] = 0 约束方程
     * @author   yangqiuyou
     * @date     2025.05.15
     */
    static  void TriConstrantEquation (const SG::Algebra::Point&                 Gi,
                                       const SG::Algebra::PointArray&            planeGlobal,
                                       SG::Algebra::Matrixd& _OUT                T,
                                       SG::Algebra::Matrixd& _OUT                R);

     /** @brief       求解四边形约束方程
     *
     * @param         Gi            投影点全局坐标   
     * @param         planeGlobal   壳面节点全局坐标
     * @param[out]    T             壳面转换矩阵
     * @param[out]    R             R*[u_A; u_Shell_G] = 0 约束方程
     * @author   yangqiuyou
     * @date     2025.05.15
     */
    static  void QuadConstrantEquation (const SG::Algebra::Point&                 Gi,
                                        const SG::Algebra::PointArray&            planeGlobal,
                                        SG::Algebra::Matrixd& _OUT                T,
                                        SG::Algebra::Matrixd& _OUT                R);

    virtual void Initialize (SG::DataStructure::FEM::ElementTypes type) override;
    virtual void ComputeElementMatries (const SG::DBManager::DBServiceFactorySP dbServiceFactory) override;
    virtual void DataRecovery (const SG::DBManager::DBServiceFactorySP             dbServiceFactory,
                               int                                                 subcaseId,
                               SG::DataStructure::Common::Real time,
                               const std::vector<SG::DataStructure::Common::Real>& globalDisplacement) override;
    virtual void ComputeStressStiffness (const SG::DBManager::DBServiceFactorySP dbServiceFactory, int staticSubId) override;

    static ElementCalculatorSP Create ()
    {
        return std::make_shared<CweldCalculator> ();
    }

        /**
     * @brief 计算CWELD单元内力
     * 
     * @param [out] elementInternalForce CWELD单元内力
     * @author   yangqiuyou
     * @date     2025.09.16
     */
    static void ComputeElementInternalForce(const SG::DBManager::DBServiceFactorySP             dbServiceFactory,
                                            const std::vector<SG::DataStructure::Common::Real>& globalDisplacement,
                                            _OUT SG::Algebra::Matrixd&                          elementInternalForce);
  private:
};
SG_FEMSOLVER_ELEMENT_NAMESPACE_CLOSE